/**
 * @file MeshProcessor.cpp
 * @brief 网格处理器类的实现
 * 
 * 实现了节点间属性插值的核心功能，包括：
 * 1. 高性能节点数据读取和处理
 * 2. 并行化的插值计算
 * 3. 基于KD树的快速空间搜索
 * 4. 自适应插值算法选择
 */

#include "MeshProcessor.h"
#include "FileIO.h"
#include "Interpolator.h"
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <omp.h>
#include <chrono>

// 初始化静态成员
size_t MeshProcessor::K_NEAREST_POINTS = 8;

/**
 * @brief 构造函数
 */
MeshProcessor::MeshProcessor(const std::string &known_nodes_file,
                           const std::string &unknown_nodes_file,
                           const std::string &output_file)
    : known_nodes_file(known_nodes_file),
      unknown_nodes_file(unknown_nodes_file),
      output_file(output_file)
{
    // 设置OpenMP线程数
    #ifdef _OPENMP
    omp_set_num_threads(omp_get_num_procs());
    #endif

    // 预分配内存
    known_nodes.reserve(2000000);
    unknown_nodes.reserve(1000000);
    results.reserve(1000000);
}

/**
 * @brief 设置K近搜索的邻居
 */
void MeshProcessor::setKNearestPoints(size_t k)
{
    K_NEAREST_POINTS = k;
}

/**
 * @brief 执行节点处理的主函数
 */
void MeshProcessor::process()
{
    try
    {
        FileIO::readKnownNodes(known_nodes_file, known_nodes);
        FileIO::readUnknownNodes(unknown_nodes_file, unknown_nodes);

        std::vector<std::pair<Point3D, double>> points;
        points.reserve(known_nodes.size());
        for (const auto &node : known_nodes)
        {
            points.emplace_back(node.point, node.s1_value);
        }
        kdtree.build(points);

        performInterpolation();
        FileIO::saveResults(output_file, results);
    }
    catch (const std::exception &e)
    {
        throw std::runtime_error("处理过程中发生错误: " + std::string(e.what()));
    }
}

/**
 * @brief 执行插值计算
 * 
 * 并行计算策略:
 * 1. 使用OpenMP并行处理大规模数据
 * 2. 动态调度提高负载均衡
 * 3. 使用块处理提高缓存命中率
 * 4. 线程本地存储减少同步开销
 * 5. 批量结果合并减少锁竞争
 * 6. 最后对结果排序保证输出顺序
 */
void MeshProcessor::performInterpolation()
{
    // 创建插值器实例
    Interpolator interpolator(kdtree);

    // 设置块大小
    const size_t CHUNK_SIZE = 1024;  // 每个线程处理的块大小
    const size_t total_points = unknown_nodes.size();
    const size_t num_chunks = (total_points + CHUNK_SIZE - 1) / CHUNK_SIZE;

    // 使用OpenMP并行处理
    #pragma omp parallel
    {
        // 线程本地存储
        std::vector<Result> local_results;
        local_results.reserve(CHUNK_SIZE);

        // 使用有符号整型作为循环索引
        #pragma omp for schedule(dynamic)
        for (int i = 0; i < static_cast<int>(num_chunks); ++i)
        {
            size_t start = static_cast<size_t>(i) * CHUNK_SIZE;
            size_t end = std::min(start + CHUNK_SIZE, total_points);
            processChunk(start, end, local_results);

            // 合并结果
            #pragma omp critical
            {
                results.insert(results.end(),
                             local_results.begin(),
                             local_results.end());
            }
            local_results.clear();
        }
    }

    // 对结果进行排序
    std::sort(results.begin(), results.end());
}

/**
 * @brief 处理数据块
 * @param start 块起始索引
 * @param end 块结束索引
 * @param chunk_results 块结果存储容器
 * 
 * 并行处理策略:
 * 1. 每个线程独立处理一个数据块,避免线程同步开销
 * 2. 使用线程本地存储避免共享内存访问
 * 3. 预分配结果向量减少内存分配
 * 4. 批量合并结果减少锁竞争
 * 5. 使用1-based索引满足输出要求
 */
void MeshProcessor::processChunk(size_t start, size_t end,
                               std::vector<Result> &chunk_results)
{
    Interpolator interpolator(kdtree);

    for (size_t i = start; i < end; ++i)
    {
        const auto &target = unknown_nodes[i];

        // 查找最近邻点
        auto neighbors = kdtree.findKNearest(target, K_NEAREST_POINTS);

        // 计算插值结果
        double s1_value = interpolator.calculate(target, neighbors);

        // 保存结果
        Result result;
        result.index = i + 1;  // 1-based index
        result.point = target;
        result.s1_value = s1_value;
        chunk_results.push_back(result);
    }
} 